package com.coocare.licence.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.coocare.licence.config.CacheConstants;
import com.coocare.licence.entity.SysRole;
import com.coocare.licence.entity.SysRoleMenu;
import com.coocare.licence.entity.SysUserRole;
import com.coocare.licence.mapper.SysRoleMapper;
import com.coocare.licence.mapper.SysUserRoleMapper;
import com.coocare.licence.service.ISysRoleMenuService;
import com.coocare.licence.service.ISysRoleService;
import com.coocare.licence.utils.PageDomain;
import com.coocare.licence.utils.PageUtils;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统角色表 服务实现类
 * </p>
 *
 * @author adam
 * @since 2023-12-11
 */
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl extends MPJBaseServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    private final ISysRoleMenuService roleMenuService;
    private final SysUserRoleMapper userRoleMapper;


    @Override
    public PageUtils pageInfo(PageDomain pageDomain, String name) {
        var query = Wrappers.lambdaQuery(SysRole.class);
        query.like(ObjectUtil.isNotEmpty(name), SysRole::getRoleName, name);
        return new PageUtils(this.baseMapper.selectPage(new Page<>(pageDomain.getPageNo(), pageDomain.getPageSize()), query));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object change(Long id, Boolean status) {
        SysRole sysRole = new SysRole();
        sysRole.setRoleId(id);
        sysRole.setEnable(status);
        this.baseMapper.updateById(sysRole);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object delById(Long id) {
        var query = Wrappers.lambdaQuery(SysRoleMenu.class);
        query.eq(SysRoleMenu::getRoleId, id);
        var list = roleMenuService.list(query);
        if (ObjectUtil.isNotEmpty(list)) {
            throw new RuntimeException("role.has.menu");
        }
        return removeById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Object assignMenu(Long roleId, List<Long> menuIds) {
        roleMenuService.remove(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, roleId));
        var list = menuIds.stream().map(menuId -> {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(roleId);
            sysRoleMenu.setMenuId(menuId);
            return sysRoleMenu;
        }).collect(Collectors.toList());
        roleMenuService.saveBatch(list);
        return Boolean.TRUE;
    }

    @Override
    public List<SysRole> getRoleByUid(Long userId) {
        var sysUserRoles = userRoleMapper.selectList(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, userId));
        if (ObjectUtil.isEmpty(sysUserRoles)) {
            throw new RuntimeException("role.not.exist");
        }
        var query = Wrappers.lambdaQuery(SysRole.class);
        query.in(SysRole::getRoleId, sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()));
        return this.baseMapper.selectList(query);
    }

    @Override
    public List<SysRole> findRolesByUserId(Long userId) {
        MPJLambdaWrapper wrapper = JoinWrappers.lambda(SysRole.class).selectAll(SysRole.class)
                .leftJoin(SysUserRole.class, SysUserRole::getRoleId, SysRole::getRoleId)
                .eq(SysRole::getEnable, true)
                .eq(SysUserRole::getUserId, userId);
        return selectJoinList(SysRole.class, wrapper);
    }

    @Cacheable(value = CacheConstants.ROLE_DETAILS, key = "#key", unless = "#result.isEmpty()")
    public List<SysRole> findRolesByRoleIds(List<Long> roleIdList, String key) {
        return baseMapper.selectBatchIds(roleIdList);
    }

    @Override
    public Boolean removeRoleByIds(Long[] ids) {
        roleMenuService.remove(Wrappers.<SysRoleMenu>update().lambda().in(SysRoleMenu::getRoleId, CollUtil.toList(ids)));
        return this.removeBatchByIds(CollUtil.toList(ids));
    }
}
